package com.mornd.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.mornd.consts.ShiroConst;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author mornd
 * @date 2020/12/28 - 20:17
 */
@Configuration
public class ShiroConfig {
    /**
     * 1、注入Shiro过滤器链 ShiroFilterFactoryBean
     * @param defaultWebSecurityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //添加安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //添加Shiro的内置过滤器
        Map<String,String> filterMap = new LinkedHashMap<>();
        /*1.anon:无需认证(登录)可以访问
        2.authc:必须认证才可以访问
        3.user:如果使用remember me 的功能可以直接访问
        4.perms:该资源必须得到资源权限才可以访问
        5.role:该资源必须得到角色权限才可以访问*/
        //登录页面
        filterMap.put("/","anon");
        filterMap.put("/index.html","anon");
        //图标
        filterMap.put("/summer.ico","anon");
        //静态资源
        filterMap.put("/pear_layui/**","anon");
        //验证码请求
        filterMap.put("/api/getVerify","anon");
        //语音请求
        filterMap.put("/api/getCaptchaVoice","anon");
        //登录提交请求
        filterMap.put("/api/login","anon");

        filterMap.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        //设置未登录时跳转至登录页面的请求 这里根据/跳到登录页面
        shiroFilterFactoryBean.setLoginUrl("/");
        //登陆成功跳转的url
        //shiroFilterFactoryBean.setSuccessUrl("/main");
        //设置未授权页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

        return shiroFilterFactoryBean;
    }

    /**
     * 2、创建DefaultWebSecurityManager对象，关联自定义的UserRealm对象
     * @param userRealm
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(userRealm);
        //添加shiro的session
        defaultWebSecurityManager.setSessionManager(getDefaultWebSessionManager());
        //设置记住我功能
        defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
        return defaultWebSecurityManager;
    }

    /**
     * 3、创建自定义Realm对象
     * @return
     */
    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        //设置凭证匹配器
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return userRealm;
    }

    /**
     * 凭证匹配器
     * 密码校验交给Shiro的SimpleAuthenticationInfo进行处理
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName(ShiroConst.HASH_ALGORITHM_NAME);//散列算法
        hashedCredentialsMatcher.setHashIterations(ShiroConst.HASH_ITERATIONS);//散列的次数
        return hashedCredentialsMatcher;
    }

    /**
     * 配置DefaultWebSessionManager(shiro的session的管理)
     * @return
     */
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        //设置会话过期时间，单位：毫秒(在无操作时开始计时) 这里设置10分钟
        defaultWebSessionManager.setGlobalSessionTimeout(10000 * 60);
        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
        defaultWebSessionManager.setSessionIdCookieEnabled(true);
        return defaultWebSessionManager;
    }

    /*@Bean
    public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理
        mappings.setProperty("UnauthorizedException", "403");
        r.setExceptionMappings(mappings);
        r.setDefaultErrorView("error");
        r.setExceptionAttribute("ex");     // 缺省值"exception"
        return r;
    }*/

    //整合ShiroDialect：用来整合Shiro和Thymeleaf
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    //开启Shiro控制器层的权限注解(如@RequiresRoles,@RequiresPermissions)
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    //开启aop注解支持（同上二选一）
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    //配置cookie基础属性
    public SimpleCookie simpleCookie(){
        //对应前台checkbox的name属性
        SimpleCookie cookie = new SimpleCookie("rememberMe");
        cookie.setHttpOnly(true);
        //cookie有效时间 单位秒 以下设置了7天
        cookie.setMaxAge(7 * 24 * 60 * 60);
        return cookie;
    }

    //cookie管理器
    public CookieRememberMeManager cookieRememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(simpleCookie());
        // cookieRememberMeManager.setCipherKey用来设置加密的Key,参数类型byte[],字节数组长度要求16
        cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
        return cookieRememberMeManager;
    }
}
